package cn.iocoder.yudao.im.service.Impl;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.im.client.IMClient;
import cn.iocoder.yudao.im.common.contant.IMConstant;
import cn.iocoder.yudao.im.common.enums.IMTerminalType;
import cn.iocoder.yudao.im.common.model.IMPrivateMessage;
import cn.iocoder.yudao.im.common.model.IMUserInfo;
import cn.iocoder.yudao.im.domain.NoticeImMessage;
import cn.iocoder.yudao.im.enums.MessageStatus;
import cn.iocoder.yudao.im.enums.MessageType;
import cn.iocoder.yudao.im.mapper.NoticeImMessageMapper;
import cn.iocoder.yudao.im.service.NoticeImMessageService;
import cn.iocoder.yudao.im.util.BeanUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;

/**
 * <p>
 * 消息表 服务实现类
 * </p>
 *
 * @author zcc
 * @since 2024-05-22
 */
@Service
public class NoticeImMessageServiceImpl extends ServiceImpl<NoticeImMessageMapper, NoticeImMessage> implements NoticeImMessageService {

    // todo   Spring  注入失败
//    @Autowired
//    @Qualifier(value = "sensitiveFilterUtil")
//    SensitiveFilterUtil sensitiveFilterUtil;
    @Resource
    IMClient imClient;

    @Override
    public Long sendMessage(NoticeImMessage noticeImMessage) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();

        NoticeImMessage msg = new NoticeImMessage();
        // 保存消息
        BeanUtils.copyProperties(noticeImMessage, msg);
        msg.setSendId(loginUser.getId());
        msg.setStatus(MessageStatus.UNSEND.code());
        msg.setSendTime(LocalDateTime.now());
        this.save(msg);
        // 过滤消息内容 todo
//        String content = sensitiveFilterUtil.filter(noticeImMessage.getContent());
//        msg.setContent(content);
        msg.setContent(noticeImMessage.getContent());
        // 推送消息
        IMPrivateMessage<NoticeImMessage> sendMessage = new IMPrivateMessage<>();
        sendMessage.setSender(new IMUserInfo(loginUser.getId(), 0));
        sendMessage.setRecvId(msg.getRecvId());
        sendMessage.setSendToSelf(true);
        sendMessage.setData(msg);
        sendMessage.setSendResult(true);
        imClient.sendPrivateMessage(sendMessage);
        return msg.getId();
    }

    @Override
    public CommonResult recallMessage(Long id) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        NoticeImMessage msg = this.getById(id);
        if (Objects.isNull(msg)) {
            return CommonResult.error(500, "消息不存在");
        }
        if (!msg.getSendId().equals(loginUser.getId())) {
            return CommonResult.error(500, "这条消息不是由您发送,无法撤回");

        }
        long epochMilli = msg.getSendTime().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        if (System.currentTimeMillis() - epochMilli > IMConstant.ALLOW_RECALL_SECOND * 1000) {
            return CommonResult.error(500, "消息已发送超过5分钟，无法撤回");
        }
        // 修改消息状态
        msg.setStatus(MessageStatus.RECALL.code());
        this.updateById(msg);
        // 推送消息
        NoticeImMessage msgInfo = new NoticeImMessage();
        BeanUtils.copyProperties(msg, msgInfo);
        msgInfo.setType(MessageType.RECALL.code());
        msgInfo.setSendTime(LocalDateTime.now());
        msgInfo.setContent("对方撤回了一条消息");

        IMPrivateMessage<NoticeImMessage> sendMessage = new IMPrivateMessage<>();
        sendMessage.setSender(new IMUserInfo(loginUser.getId(), 0));
        sendMessage.setRecvId(msgInfo.getRecvId());
        sendMessage.setSendToSelf(false);
        sendMessage.setData(msgInfo);
        sendMessage.setSendResult(false);
        imClient.sendPrivateMessage(sendMessage);

        // 推给自己其他终端
        msgInfo.setContent("你撤回了一条消息");
        sendMessage.setSendToSelf(true);
        sendMessage.setRecvTerminals(Collections.emptyList());
        imClient.sendPrivateMessage(sendMessage);
        return CommonResult.success("");

    }

    @Override
    public List<NoticeImMessage> findHistoryMessage(Long friendId, Long page, Long size) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();


        page = page > 0 ? page : 1;
        size = size > 0 ? size : 10;
        Long userId = loginUser.getId();
        long stIdx = (page - 1) * size;
        QueryWrapper<NoticeImMessage> wrapper = new QueryWrapper<>();
        wrapper.lambda().and(wrap -> wrap.and(wp -> wp.eq(NoticeImMessage::getSendId, userId).eq(NoticeImMessage::getRecvId, friendId)).or(wp -> wp.eq(NoticeImMessage::getRecvId, userId).eq(NoticeImMessage::getSendId, friendId))).ne(NoticeImMessage::getStatus, MessageStatus.RECALL.code()).orderByDesc(NoticeImMessage::getId).last("limit " + stIdx + "," + size);

        List<NoticeImMessage> messages = this.list(wrapper);
        return messages;
    }

    @Override
    public CommonResult pullOfflineMessage(Long minId) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();

        if (!imClient.isOnline(loginUser.getId())) {
            return CommonResult.error(500, "网络连接失败，无法拉取离线消息");

        }
        // 获取当前用户的消息
        LambdaQueryWrapper<NoticeImMessage> queryWrapper = Wrappers.lambdaQuery();
        // 只能拉取最近1个月的1000条消息
        Date minDate = DateUtils.addMonths(new Date(), -1);
        queryWrapper.gt(NoticeImMessage::getId, minId).ge(NoticeImMessage::getSendTime, minDate).ne(NoticeImMessage::getStatus, MessageStatus.RECALL.code()).and(wrap -> wrap.and(wp -> wp.eq(NoticeImMessage::getSendId, loginUser.getId())
//                                        .eq(FancyOfficeImMessage::getRecvId, userId)
        ).or(wp -> wp.eq(NoticeImMessage::getRecvId, loginUser.getId())
//                                .eq(FancyOfficeImMessage::getSendId, userId)
        )).orderByDesc(NoticeImMessage::getId).last("limit 1000");
        List<NoticeImMessage> messages = this.list(queryWrapper);

        // 推送消息
        for (NoticeImMessage m : messages) {
            IMPrivateMessage<NoticeImMessage> sendMessage = new IMPrivateMessage<>();
            sendMessage.setSender(new IMUserInfo(m.getSendId(), IMTerminalType.WEB.code()));
            sendMessage.setRecvId(loginUser.getId());
            sendMessage.setRecvTerminals(Arrays.asList(0));
            sendMessage.setSendToSelf(false);
            sendMessage.setData(m);
            sendMessage.setSendResult(true);
            imClient.sendPrivateMessage(sendMessage);
        }
        // 关闭加载中标志
        this.sendLoadingMessage(false);
        return CommonResult.success("");
    }

    @Override
    public void readedMessage(Long friendId) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        // 推送消息给自己，清空会话列表上的已读数量
        NoticeImMessage msgInfo = new NoticeImMessage();
        msgInfo.setType(MessageType.READED.code());
        msgInfo.setSendId(loginUser.getId());
        msgInfo.setRecvId(friendId);
        IMPrivateMessage<NoticeImMessage> sendMessage = new IMPrivateMessage<>();
        sendMessage.setData(msgInfo);
        sendMessage.setSender(new IMUserInfo(loginUser.getId(), 0));
        sendMessage.setSendToSelf(true);
        sendMessage.setSendResult(false);
        imClient.sendPrivateMessage(sendMessage);
        // 推送回执消息给对方，更新已读状态
        msgInfo = new NoticeImMessage();
        msgInfo.setType(MessageType.RECEIPT.code());
        msgInfo.setSendId(loginUser.getId());
        msgInfo.setRecvId(friendId);
        sendMessage = new IMPrivateMessage<>();
        sendMessage.setSender(new IMUserInfo(loginUser.getId(), 0));
        sendMessage.setRecvId(friendId);
        sendMessage.setSendToSelf(false);
        sendMessage.setSendResult(false);
        sendMessage.setData(msgInfo);
        imClient.sendPrivateMessage(sendMessage);
        // 修改消息状态为已读
        LambdaUpdateWrapper<NoticeImMessage> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(NoticeImMessage::getSendId, friendId).eq(NoticeImMessage::getRecvId, loginUser.getId()).eq(NoticeImMessage::getStatus, MessageStatus.SENDED.code()).set(NoticeImMessage::getStatus, MessageStatus.READED.code());
        this.update(updateWrapper);
    }

    @Override
    public Long getMaxReadedId(Long userId) {

        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();

        LambdaQueryWrapper<NoticeImMessage> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(NoticeImMessage::getSendId, loginUser.getId()).eq(NoticeImMessage::getRecvId, userId).eq(NoticeImMessage::getStatus, MessageStatus.READED.code()).orderByDesc(NoticeImMessage::getId).select(NoticeImMessage::getId).last("limit 1");
        NoticeImMessage message = this.getOne(wrapper);
        if (Objects.isNull(message)) {
            return -1L;
        }
        return message.getId();
    }

    @Override
    public Long getCommunicateCount(Long userId) {
        return this.baseMapper.selectCount(new LambdaQueryWrapper<NoticeImMessage>().eq(NoticeImMessage::getSendId, userId).groupBy(NoticeImMessage::getRecvId).last("limit 1"));
    }


    private void sendLoadingMessage(Boolean isLoadding) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        NoticeImMessage msgInfo = new NoticeImMessage();
        msgInfo.setType(MessageType.LOADDING.code());
        msgInfo.setContent(isLoadding.toString());
        IMPrivateMessage sendMessage = new IMPrivateMessage<>();
        sendMessage.setSender(new IMUserInfo(loginUser.getId(), 0));
        sendMessage.setRecvId(loginUser.getId());
        sendMessage.setRecvTerminals(Arrays.asList(0));
        sendMessage.setData(msgInfo);
        sendMessage.setSendToSelf(false);
        sendMessage.setSendResult(false);
        imClient.sendPrivateMessage(sendMessage);
    }
}
